#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include "fsm.h"

int fsm_init(fsm_t **my_fsm, int rfd, int wfd)
{
    int save;
    *my_fsm = malloc(sizeof(fsm_t));
    if (NULL == *my_fsm)
        return -1;
    (*my_fsm)->rfd = rfd;
    (*my_fsm)->wfd = wfd;
    (*my_fsm)->state = STATE_R;
    memset((*my_fsm)->buf, '\0', BUFSIZE);
    (*my_fsm)->read_cnt = (*my_fsm)->pos = 0;
    (*my_fsm)->errmsg = NULL;

    // 将状态机对象一定保证非阻塞
    save = fcntl((*my_fsm)->rfd, F_GETFL);
    fcntl((*my_fsm)->rfd, F_SETFL, save | O_NONBLOCK);
    save = fcntl((*my_fsm)->wfd, F_GETFL);
    fcntl((*my_fsm)->wfd, F_SETFL, save | O_NONBLOCK);

    return 0;
}

int fsm_drive(fsm_t *my_fsm)
{
    int ret;

    switch (my_fsm->state) {
        case STATE_R:
            // 非阻塞IO
            my_fsm->read_cnt = read(my_fsm->rfd, my_fsm->buf, BUFSIZE);
            if (-1 == my_fsm->read_cnt) {
                if (EAGAIN == errno) {
                    // 假错 没有数据
                    ;
                } else {
                    my_fsm->state = STATE_E;
                    my_fsm->errmsg = "read()";
                }
            } else if (0 == my_fsm->read_cnt) {
                my_fsm->state = STATE_T;
            } else {
                my_fsm->state = STATE_W;
                my_fsm->pos = 0;
            }
            break;
        case STATE_W:
            ret = write(my_fsm->wfd, my_fsm->buf + my_fsm->pos, my_fsm->read_cnt);
            if (-1 == ret) {
                my_fsm->state = STATE_E;
                my_fsm->errmsg = "write()";
            } else if (ret < my_fsm->read_cnt) {
                // 没写完
                my_fsm->read_cnt -= ret;
                my_fsm->pos += ret;
            } else {
                my_fsm->state = STATE_R;
            }
            break;
        case STATE_E:
            perror(my_fsm->errmsg);
            my_fsm->state = STATE_T;
            break;
        case STATE_T:
            break;
        default:
            break;
    }
}

void fsm_destroy(fsm_t **my_fsm)
{
    free(*my_fsm);
    *my_fsm = NULL;
}

